﻿/**
 * @file console.c
 * @date 23.5.7
 * @author yrz
 * @brief 命令行相关处理
 * @version 0.1
 * @status Stable

**/ 
#include <stdarg.h>

#include "types.h"
#include "param.h"
//#include "spinlock.h"
//#include "sleeplock.h"
#include "fs.h"
#include "file.h"
#include "memlayout.h"
#include "riscv.h"
#include "defs.h"
#include "proc.h"

#define BACKSPACE 0x100
#define C(x)  ((x)-'@')

/**
 * @brief 将字符输送到uart输出寄存器
 * @param c 输入字符
*/
void
consputc(int c)
{
    if (c == BACKSPACE) {
        // 输入回车, 则用空格覆盖.
        uartputc_sync('\b'); uartputc_sync(' '); uartputc_sync('\b');
    }
    else {
        uartputc_sync(c);
    }
}


struct {
    //struct spinlock lock; // console互斥锁

    // 输入
#define INPUT_BUF_SIZE 128      //输入缓冲区大小
    char buf[INPUT_BUF_SIZE];   //输入缓冲区
    uint r;  // 读
    uint w;  // 写
    uint e;  // 编辑
} cons;


/**
 * @brief console输入中断处理程序
 
*/
void
consoleintr(int c)
{
    //acquire(&cons.lock);

    switch (c) {
    case C('P'):  // 输入P，打印进程列表
        procdump();
        break;
    case C('U'):  // 输入U，杀死这一行
        while (cons.e != cons.w &&
            cons.buf[(cons.e - 1) % INPUT_BUF_SIZE] != '\n') {
            cons.e--;
            consputc(BACKSPACE);
        }
        break;
    case C('H'): // 输入H，回车
    case '\x7f': // 转义后为del，删除
        if (cons.e != cons.w) {
            cons.e--;
            consputc(BACKSPACE);
        }
        break;
    default:
        if (c != 0 && cons.e - cons.r < INPUT_BUF_SIZE) {
            c = (c == '\r') ? '\n' : c;

            // 回显给用户.
            consputc(c);

            
            // 存储consoleread读到的数据
            cons.buf[cons.e++ % INPUT_BUF_SIZE] = c;

            if (c == '\n' || c == C('D') || cons.e - cons.r == INPUT_BUF_SIZE) {

                // 如果一整段到达，唤醒consoleread
                cons.w = cons.e;
                wakeup(&cons.r);
            }
        }
        break;
    }

    //release(&cons.lock);
}



/**
 * @brief console写进程，用户调用write（）时跳转到这里
 * @param user_src 来着用户地址还是内核地址
 * @param src 地址
 * @param n 字节数
*/
int
consolewrite(int user_src, uint64 src, int n)
{
    int i;

    for (i = 0; i < n; i++) {
        char c;
        if (either_copyin(&c, user_src, src + i, 1) == -1)
            break;
        uartputc(c);
    }

    return i;
}


/**
 * @brief console读进程，用户调用read（）时跳转到这里
 * @param user_dst 来着用户地址还是内核地址
 * @param dst 地址
 * @param n 字节数
*/
int
consoleread(int user_dst, uint64 dst, int n)
{
    uint target;
    int c;
    char cbuf;

    target = n;
    //acquire(&cons.lock);
    while (n > 0) {

        // 等待中断处理将输入放入cons缓冲区
        while (cons.r == cons.w) {
            if (killed(myproc())) {
                //release(&cons.lock);
                return -1;
            }
            sleep(&cons.r); //设为忙等
        }

        c = cons.buf[cons.r++ % INPUT_BUF_SIZE];

        if (c == C('D')) {  // end-of-file
            if (n < target) {
                // Save ^D for next time, to make sure
                // caller gets a 0-byte result.
                // 没太看懂这块在干什么
                cons.r--;
            }
            break;
        }

        
        // 将输入拷贝到用户空间缓冲区
        cbuf = c;
        if (either_copyout(user_dst, dst, &cbuf, 1) == -1)
            break;

        dst++;
        --n;

        if (c == '\n') {

            // 一整行抵达，返回到用户级read（）
            break;
        }
    }
    //release(&cons.lock);

    return target - n;
}


void
consoleinit(void)
{
	//initlock(&cons.lock, "cons");

	uartinit();


    //将命令行的读写与读写系统调用相关联
	devsw[CONSOLE].read = consoleread;
	devsw[CONSOLE].write = consolewrite;
}